import { inject, provide, reactive, toRefs } from '@vue/composition-api'
import { fabric } from 'fabric'
import { v4 as uuidv4 } from 'uuid'

const key = Symbol('canvas')
export default function useCanvas () {
  return inject(key)
}

export function createCanvas (context) {
  const state = reactive({
    canvas: null,
    layerArr: [],
    editLayer: null,
    editLayerUUID: '',
    tempPosition: {}
  })

  /**
   * 初始化画布
   * @param {String} id Canvas画布id 
   */
  function initCanvas (id) {
    fabric.Object.prototype.set({
      transparentCorners: false,
      cornerStrokeColor:'#3B9BF4', //边角描边颜色
      cornerColor: 'rgba(255,255,255,1)', //边角颜色
      cornerSize: 12, //边角大小
      borderScaleFactor:2, //描边边框大小
      borderColor:'#3B9BF4', //描边边框颜色,
    })
    state.canvas = new fabric.Canvas(id)
    // 校验边界
    state.canvas.on('mouse:down', () => {
      initVerifyBorder()
    })
    state.canvas.on('mouse:up', () => {
     verifyBorder()
    })
    console.log('canvas', state.canvas)
  }

  /**
   * 通过文件批量加载图片
   * @param { File[] } files 
   * @returns 
   */
  function laodImageByFiles (files) {
    if (files && files.length === 0) return
    for (let file of files) {
      if (!/\.(jpg|jpeg|png|gif|GIF|JPG|PNG|webp)$/.test(file.name)) {
        context.$message.error('文件格式错误， 请上传图片文件')
        return
      }
    }
    const imageOptions = () => import('../components/img/desc').options
    const PromiseArr = []
    for(const file of files) {
      const src = URL.createObjectURL(file)
      const tempImg = document.createElement('img')
      tempImg.src = src
        // 图片过大需要缩小处理
        const loadPromise = new Promise ((resolve) => {
          tempImg.onload = () => {
            const { width, height } = tempImg
            const imgZoom = height > width ? (height > 800 ? 800 / height : 1 ) : (width > 800 ? 800 / width : 1) // 计算宽高缩放比
            const loadImage = new fabric.Image(tempImg,{ ...imageOptions, uuid: uuidv4(), width, height }) //设置图片位置和样子
            loadImage.scale(imgZoom) // 缩放到合适大小
            state.canvas.viewportCenterObject(loadImage)
            loadImage.on('selected', () => { handleSelectLayer(loadImage) })
            state.canvas.add(loadImage)//加入到canvas中
            resolve(loadImage)
          }
        })
        PromiseArr.push(loadPromise)
      }
    // 图片加载完再执行
    Promise.all(PromiseArr).then((imageList) => {
      state.canvas.setActiveObject(imageList[0])
      getLayerArr ()
    })
  }

  /**
   * 拖拽添加图层
   * @param {event} e 
   * @returns 
   */
  function handleDrop (e) {
    e.preventDefault()
    if (e.dataTransfer.files.length !== 0) { // 拖拽进来为文件时
      laodImageByFiles(e.dataTransfer.files)
      return
    }
    // 非文件且时正常图层
    const data = e.dataTransfer.getData('layer__data')
    if (!data) return
    const { p, desc } = JSON.parse(data)
    const options = { // 公共参数
      uuid: uuidv4(),
      left: (e.offsetX - p.x),
      top: (e.offsetY - p.y),
      ...desc.options
    }
    let fabricObject = {}
    if (desc.type === 'img') {
      const imageEle = document.getElementById('init-img')
      fabricObject = new fabric.Image(imageEle,{  //设置图片位置和样子
        ...options,
        width:imageEle.width,
        height:imageEle.height,
      });
    } else {
      fabricObject = new fabric.Textbox('双击进行编辑', { ...options })
    }
    fabricObject.on('selected', () => { handleSelectLayer(fabricObject) })
    state.canvas.add(fabricObject).setActiveObject(fabricObject) //加入到canvas中
    getLayerArr()
  }

  // 获取所有图层
  function getLayerArr () {
    state.layerArr = state.canvas.getObjects().reverse()  //图层列表倒叙排
  }

  // 删除当前选中图层
  function removeLayer (layer, index) {
    if (!layer.selectable) { return }
    state.layerArr.splice(index, 1)
    setTimeout(() => { // 删除最后一个图层需要异步执行
      if (layer.uuid === state.editLayer.uuid) {
        state.editLayer = null
        state.editLayerUUID = ''
      }
      state.canvas.remove(layer)
    }, 0);
  }

  //锁住图层
  function lockOption (layer){
    layer.lockMovementX = true
    layer.lockMovementY = true
    layer.lockRotation = true
    layer.lockScalingFlip = true
    layer.lockScalingX = true
    layer.lockScalingY = true
    layer.lockUniScaling = true
  }

  //解锁图层
  function unLockOption (layer){
    layer.lockMovementX = false
    layer.lockMovementY = false
    layer.lockRotation = false
    layer.lockScalingFlip = false
    layer.lockScalingX = false
    layer.lockScalingY = false
    layer.lockUniScaling = false
  }

  /**
   * 选中图层后处理事件
   */
  function handleSelectLayer (layer) {
    console.log('selected', layer)
    state.editLayerUUID = layer.uuid
    state.editLayer = layer
  }

  /**
   * 获取校验边界图层的初始化数据，方便回滚
   * @returns 
   */
  function initVerifyBorder () {
    const editLayer = state.canvas.getActiveObject() || state.editLayer
    if (!editLayer) return
    const { width, height, top, left, scaleX, scaleY } = editLayer
    state.tempPosition = { width, height, top, left, scaleX, scaleY }
  }

  /**
   * 校验图层四个角是否有超出边界的情况
   * @returns 
   */
  function verifyBorder () {
    const editLayer = state.canvas.getActiveObject() || state.editLayer
    if (!editLayer) return
    const leavePoint = { overX: [], downX: [], overY: [], downY: [] }
    for (const position in editLayer.aCoords) {
      const { x, y } = editLayer.aCoords[position]
      x > 800 && leavePoint.overX.push(x)
      x < 0 && leavePoint.downX.push(x)
      y > 800 && leavePoint.overY.push(y)
      y < 0 && leavePoint.downY.push(y)
    }
    const leavePointNum = Object.values(leavePoint).map(point => point.length)
    if (leavePointNum.includes(4)) {
      for (const prop in state.tempPosition) {
        editLayer[prop] = state.tempPosition[prop]
      }
      state.tempPosition = {}
      state.canvas.renderAll()
      return context.$message.error('图层不可以完全离开画布')
    } else if (leavePointNum.reduce((a, b) => a + b) > 0) {
      const borderColor = editLayer.borderColor
      if (borderColor === '#FF0000') return
      editLayer.set('borderColor', '#FF0000')
      state.canvas.renderAll()
      return context.$message.warning('图层部分内容已离开画布')
    }
    editLayer.set('borderColor', '#3B9BF4')
    state.canvas.renderAll()
  }

  function canvasToJson () {
    const canvasArr = state.canvas.toJSON().objects
    console.log(canvasArr);
    let Json = `{"objects": ${JSON.stringify(canvasArr)}}`
    state.canvas.loadFromJSON(Json)
    state.canvas.getObjects()[0].text = '替换文字'
    state.canvas.renderAll()
  }

  function addImage () {
    const img = state.canvas.getActiveObject()
    // 使用 setSrc 方法更改图片，第二个参数是回调函数，在回调函数里刷新一下 canvas 即可
    img.setSrc('https://api.map.baidu.com/lbsapi/getpoint/Images/logo.gif', () => {
      // state.canvas.viewportCenterObject(img)
      state.canvas.renderAll()
    })
  }
  

  provide(key, {
    ...toRefs(state),
    initCanvas,
    laodImageByFiles,
    getLayerArr,
    removeLayer,
    lockOption,
    unLockOption,
    handleDrop,
    verifyBorder,
    initVerifyBorder,
    canvasToJson,
    addImage
  })
}
